import React, { useState, useRef } from "react";
import {
  Modal,
  View,
  TouchableWithoutFeedback,
  Dimensions,
  LayoutChangeEvent,
  Platform,
  TouchableHighlight,
} from "react-native";
import { ContextMenuProps, MenuItemProps, MenuPosition } from "./types";
import MenuItem from "./MenuItem";
import styles from "./index.styles";
import { useTheme } from "@/contexts/ThemeContext";

// 获取屏幕尺寸
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get("window");

// 安全区域外边距
const SCREEN_MARGIN = 10;

// 紧贴效果的微调值（用于消除可能的间隙）
const TIGHT_FIT_ADJUSTMENT = 2; // 使用正值提供适当的间距

/**
 * @author BelovedLYC
 * ContextMenu - 可自定义的上下文菜单组件
 *
 * 提供基于长按触发的上下文菜单功能，支持多种定位方式和自定义样式。
 * 可用于列表项、卡片、图片等多种元素，为用户提供上下文相关的操作选项。
 *
 * 特性:
 * - 支持长按和点击事件同时处理
 * - 自动计算最佳位置，避免超出屏幕边界
 * - 多种预设位置（上、下、左、右、元素底部）
 * - 完全可自定义的外观和行为
 * - 支持图标和文本自定义
 *
 * @example
 * ```tsx
 * <ContextMenu
 *   items={[
 *     { id: 'edit', label: '编辑', icon: 'pencil-outline', onPress: handleEdit },
 *     { id: 'delete', label: '删除', icon: 'trash-outline', onPress: handleDelete }
 *   ]}
 *   position={MenuPosition.ITEM_BOTTOM}
 *   onPress={handlePress}
 * >
 *   <View>
 *     <Text>长按或点击此元素</Text>
 *   </View>
 * </ContextMenu>
 * ```
 */
const ContextMenu: React.FC<ContextMenuProps> = ({
  children,
  items,
  onClose,
  onOpen,
  onPress,
  closeOnSelect = true,
  menuStyle,
  menuItemStyle,
  menuItemTextStyle,
  position = MenuPosition.AUTO,
  positionOffset = { x: 0, y: 0 },
  renderIcon,
  maxWidth = 280,
  minWidth = 150,
  showShadow = true,
}) => {
  const { colors } = useTheme();
  const [visible, setVisible] = useState(false);
  const [menuLayout, setMenuLayout] = useState({ width: 0, height: 0 });
  const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 });
  const childrenLayout = useRef({ width: 0, height: 0 });
  const childrenPosition = useRef({ x: 0, y: 0 });
  const touchPosition = useRef({ x: 0, y: 0 });
  const childrenRef = useRef<View>(null);
  const lastTapRef = useRef<number>(0);

  /**
   * 处理长按事件，显示上下文菜单
   * 保存触摸位置和触发元素的位置与尺寸，用于后续计算菜单位置
   */
  const handleOpen = ({ nativeEvent }: any) => {
    // 保存触摸位置
    touchPosition.current = {
      x: nativeEvent.pageX,
      y: nativeEvent.pageY,
    };

    // 测量触发元素位置
    childrenRef.current?.measure((x, y, width, height, pageX, pageY) => {
      childrenLayout.current = {
        width,
        height,
      };

      // 保存元素在屏幕上的绝对位置
      childrenPosition.current = {
        x: pageX,
        y: pageY,
      };

      // 显示菜单
      setVisible(true);
      onOpen?.();
    });
  };

  /**
   * 处理普通点击事件
   * 当用户短暂点击（而非长按）时触发
   */
  const handlePress = () => {
    // 调用外部传入的onPress函数
    onPress?.();
  };

  /**
   * 处理触摸开始事件
   * 记录触摸开始时间，用于区分点击和长按
   */
  const handleTouch = () => {
    lastTapRef.current = Date.now();
  };

  /**
   * 处理触摸结束事件
   * 根据触摸持续时间判断是点击还是长按
   */
  const handleTouchEnd = () => {
    if (Date.now() - lastTapRef.current < 300) {
      handlePress();
    }
  };

  /**
   * 处理菜单关闭事件
   * 关闭菜单并触发onClose回调
   */
  const handleClose = () => {
    setVisible(false);
    onClose?.();
  };

  /**
   * 处理菜单项选择事件
   * 执行菜单项的onPress回调，并根据closeOnSelect决定是否关闭菜单
   */
  const handleMenuItemSelect = (item: MenuItemProps) => {
    item.onPress?.();
    if (closeOnSelect) {
      handleClose();
    }
  };

  /**
   * 计算菜单位置
   * 根据配置的position参数和屏幕边界动态调整菜单位置
   *
   * @param menuWidth 菜单宽度
   * @param menuHeight 菜单高度
   */
  const calculateMenuPosition = (menuWidth: number, menuHeight: number) => {
    // 初始位置基于触摸点
    let x = touchPosition.current.x;
    let y = touchPosition.current.y;

    // 根据位置参数调整
    switch (position) {
      case MenuPosition.TOP:
        // 将菜单放置在触发点上方
        x = x - menuWidth / 2;
        y = y - menuHeight - 10;
        break;
      case MenuPosition.BOTTOM:
        // 将菜单放置在触发点下方
        x = x - menuWidth / 2;
        y = y + 10;
        break;
      case MenuPosition.LEFT:
        // 将菜单放置在触发点左侧
        x = x - menuWidth - 10;
        y = y - menuHeight / 2;
        break;
      case MenuPosition.RIGHT:
        // 将菜单放置在触发点右侧
        x = x + 10;
        y = y - menuHeight / 2;
        break;
      case MenuPosition.ITEM_BOTTOM:
        // 将菜单水平居中于元素
        x =
          childrenPosition.current.x +
          (childrenLayout.current.width - menuWidth) / 2;

        // 将菜单放置在元素底部，带有适当间距
        y =
          childrenPosition.current.y +
          childrenLayout.current.height +
          TIGHT_FIT_ADJUSTMENT;

        // 检查是否超出屏幕底部
        if (y + menuHeight > SCREEN_HEIGHT - SCREEN_MARGIN) {
          // 如果菜单会超出屏幕底部，改为显示在元素上方
          y = childrenPosition.current.y - menuHeight - TIGHT_FIT_ADJUSTMENT;
        }
        break;
      case MenuPosition.AUTO:
      default:
        // 默认放在触摸点右下方
        x = x + 5;
        y = y + 5;

        // 检查右边界
        if (x + menuWidth > SCREEN_WIDTH - SCREEN_MARGIN) {
          x = SCREEN_WIDTH - SCREEN_MARGIN - menuWidth;
        }

        // 检查底部边界
        if (y + menuHeight > SCREEN_HEIGHT - SCREEN_MARGIN) {
          y = SCREEN_HEIGHT - SCREEN_MARGIN - menuHeight;
        }

        // 检查左边界
        if (x < SCREEN_MARGIN) {
          x = SCREEN_MARGIN;
        }

        // 检查顶部边界
        if (y < SCREEN_MARGIN) {
          y = SCREEN_MARGIN;
        }
        break;
    }

    // 应用偏移量
    x += positionOffset.x;
    y += positionOffset.y;

    setMenuPosition({ x, y });
  };

  /**
   * 处理菜单布局变化事件
   * 当菜单布局完成后，计算并更新菜单位置
   */
  const handleMenuLayout = (event: LayoutChangeEvent) => {
    const { width, height } = event.nativeEvent.layout;
    setMenuLayout({ width, height });
    calculateMenuPosition(width, height);
  };

  /**
   * 计算菜单容器样式
   * 根据当前上下文和配置生成最终的样式对象
   */
  const getMenuContainerStyle = () => {
    const shadowStyle = showShadow
      ? Platform.select({
          ios: { ...styles.shadowIOS, shadowColor: colors.card.shadow },
          android: { ...styles.shadowAndroid, shadowColor: colors.card.shadow },
        })
      : {};
    return [
      styles.menuContainer,
      {
        left: menuPosition.x,
        top: menuPosition.y,
        maxWidth,
        minWidth,
        backgroundColor: colors.background,
      },
      shadowStyle,
      menuStyle,
    ];
  };

  return (
    <View
      ref={childrenRef}
      onTouchEnd={handleTouchEnd}
      onTouchStart={handleTouch}
    >
      <TouchableHighlight onLongPress={handleOpen} underlayColor="transparent">
        {children}
      </TouchableHighlight>
      <Modal
        visible={visible}
        transparent
        animationType="fade"
        onRequestClose={handleClose}
      >
        <TouchableWithoutFeedback onPress={handleClose}>
          <View style={styles.overlay} />
        </TouchableWithoutFeedback>
        <View
          style={getMenuContainerStyle()}
          onLayout={handleMenuLayout}
          key={visible.toString()}
        >
          {items.map((item) => (
            <MenuItem
              key={item.id}
              label={item.label}
              onPress={() => handleMenuItemSelect(item)}
              style={[styles.menuItem, menuItemStyle]}
              textStyle={menuItemTextStyle}
              icon={
                renderIcon ? renderIcon(item.icon, 20, item.color) : item.icon
              }
              color={item.color}
              disabled={item.disabled}
            />
          ))}
        </View>
      </Modal>
    </View>
  );
};

export default ContextMenu;
